const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败

class MyPromise {
	constructor(executor) {
		// 对promise回调函数进行错误判断
		try {
			executor(this.resolve, this.reject)
		} catch (e) {
			this.reject(e);
		}
	}

	// promsie 状态 
	status = PENDING;
	// 成功之后的值
	value = undefined;
	// 失败后的原因
	reason = undefined;
	// 成功回调
	successCallback = [];
	// 失败回调
	failCallback = [];

	resolve = value => {
		// 如果状态不是等待 阻止程序向下执行
		if (this.status !== PENDING) return;
		// 将状态更改为成功
		this.status = FULFILLED;
		// 保存成功之后的值
		this.value = value;

		// 判断成功回调是否存在 如果存在 调用  
		// while循环,shift()会删除数组第一个值,直到删除完毕后 循环停止
		while (this.successCallback.length) this.successCallback.shift()()
	}

	reject = reason => {
		// 如果状态不是等待 阻止程序向下执行
		if (this.status !== PENDING) return;
		// 将状态更改为失败
		this.status = REJECTED;
		// 保存失败后的原因
		this.reason = reason;

		// 判断失败回调是否存在 如果存在 调用
		while (this.failCallback.length) this.failCallback.shift()()
	}

	then(successCallback, failCallback) {

		// 参数可选 当没有successCallback时  创建个successCallback函数  内部返回传入的值
		successCallback = successCallback ? successCallback : (value) => value;
		// 参数可选 // 抛出错误
		failCallback = failCallback ? failCallback : reason => {
			throw reason
		};
		// 链式编程返回Promise对象
		let promsie2 = new MyPromise((resolve, reject) => {
			// 下一个Promise返回的值必须为上一个成功之后的值. 所以将状态判断放入立即执行函数
			// successCallback返回值传入下一个resolve()
			if (this.status === FULFILLED) {
				// resolvePromise中拿不到promsie2, 将其变为异步
				setTimeout(() => {
					// 对then中回调函数错误进行拦截
					try {
						let x = successCallback(this.value);
						// 判断 x 的值是普通值还是promise对象
						// 如果是普通值 直接调用resolve 
						// 如果是promise对象 查看promsie对象返回的结果 
						// 再根据promise对象返回的结果 决定调用resolve 还是调用reject
						resolvePromise(promsie2, x, resolve, reject)
					} catch (e) {
						reject(e);
					}
				}, 0)
			} else if (this.status === REJECTED) {
				setTimeout(() => {
					// 对then中回调函数错误进行拦截
					try {
						let x = failCallback(this.reason);
						// 判断 x 的值是普通值还是promise对象
						// 如果是普通值 直接调用resolve 
						// 如果是promise对象 查看promsie对象返回的结果 
						// 再根据promise对象返回的结果 决定调用resolve 还是调用reject
						resolvePromise(promsie2, x, resolve, reject)
					} catch (e) {
						reject(e);
					}
				}, 0)
			} else {
				// 等待
				// 异步执行时 状态还为PENDING, 将回调函数缓存起来
				// 处理异步代码  使其规则与同步一样对.返回值进行处理
				this.successCallback.push(() => {
					setTimeout(() => {
						try {
							let x = successCallback(this.value);
							// 判断 x 的值是普通值还是promise对象
							// 如果是普通值 直接调用resolve 
							// 如果是promise对象 查看promsie对象返回的结果 
							// 再根据promise对象返回的结果 决定调用resolve 还是调用reject
							resolvePromise(promsie2, x, resolve, reject)
						} catch (e) {
							reject(e);
						}
					}, 0)
				});
				this.failCallback.push(() => {
					setTimeout(() => {
						try {
							let x = failCallback(this.reason);
							// 判断 x 的值是普通值还是promise对象
							// 如果是普通值 直接调用resolve 
							// 如果是promise对象 查看promsie对象返回的结果 
							// 再根据promise对象返回的结果 决定调用resolve 还是调用reject
							resolvePromise(promsie2, x, resolve, reject)
						} catch (e) {
							reject(e);
						}
					}, 0)
				});
			}
		})
		return promsie2
	}
	
	// ****** 模拟catch
	catch (failCallback) {
		return this.then(undefined, failCallback)
	}

	// promise.all方法实现
	static all(array) {
		console.log(array)

		let result = [];
		let index = 0; // 计数器
		return new MyPromise((resolve, reject) => {
			function addData(key, value) { // 添加

				result[key] = value;
				index++; // 每添加一个就++ 
				console.log(index, result.length, index == result.length)
				// debugger
				if (index === array.length) { // 针对异步操作 当index和**输入**数组长度相当, 则输出
					resolve(result);
				}
			}
			for (let i = 0; i < array.length; i++) {
				let current = array[i];
				if (current instanceof MyPromise) { // 判断传入的值是否为promise
					// promise 对象
					// 成功直接添加, 失败则reject
					current.then(value => addData(i, value), reason => reject(reason))
				} else {
					// 普通值
					addData(i, array[i]);
				}
			}
		})
	}

	// promise.resolve实现方法  判断传入的是否为promise
	static resolve(value) {
		if (value instanceof MyPromise) return value;
		return new MyPromise(resolve => resolve(value));
	}
	//  promise.finally实现方法
	// 无论成功|失败都将返回promise
	finally(callback) {
		return this.then(value => {
			// 为了等待异步执行完成后再执行.then()
			return MyPromise.resolve(callback()).then(() => value);
		}, reason => {
			return MyPromise.resolve(callback()).then(() => {
				throw reason
			})
		})
	}
}

function resolvePromise(promsie2, x, resolve, reject) {
	// 判断返回的Promise和当前Promise是否相等   如若相等  抛出错误
	console.log('promsie2:', promsie2, 'x:', x, promsie2 === x)
	if (promsie2 === x) {
		return reject(new TypeError('好特么难'))
	}
	// 使用 instanceof 就是判断一个实例是否属于某种类型
	if (x instanceof MyPromise) {
		// promise 对象
		// x.then(value => resolve(value), reason => reject(reason));
		x.then(resolve, reject);
	} else {
		// 普通值
		resolve(x);
	}
}
